package com.neuronbit.businessflow.flow.parser;

import com.neuronbit.businessflow.flow.clazz.*;
import com.neuronbit.businessflow.flow.project.Project;
import com.neuronbit.businessflow.intellij.model.StatefulTask;
import com.neuronbit.businessflow.intellij.model.Type;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;

import java.util.List;

/**
 * The type Auto task node.
 */
@Getter
@Setter
public class StatefulTaskNode extends StatefulTask implements CallableNode {
    /**
     * the output
     */
    private Output output;
    /**
     * exception types
     */
    private ExceptionTypeInfo[] exceptionTypes;

    private ExceptionTypeInfo[] stateCheckerExceptionTypes;

    /**
     * Instantiates a new Auto task node.
     *
     * @param id   the id
     * @param name the name
     */
    public StatefulTaskNode(String id, String name) {
        super(id, name);
    }

    public void resolveStateCheckerMethod(Project project) {
        String type = getStateChecker().getType().getQualifiedName();
        int paramCount = getStateChecker().getParams().size();
        if (getStateChecker().getMethod()==null || getStateChecker().getMethod().isBlank() || StringUtils.isBlank(type)) {
            return;
        }
        String methodName = getStateChecker().getMethod().getName();
        try {
            ClassInfo clazz = project.find(type);
            if (null == clazz) {
                throw new ClassNotFoundException(type + " is not find");
            }
            List<MethodInfo> methods = findMethodByName(clazz, methodName, paramCount);
            if (!methods.isEmpty()) {
                //TODO shunyun 2024/4/8: 多个 method 如何处理
                if (methods.size() > 1) {
                    throw new NoSuchMethodException("more than one method found with " + methodName + " in class " + type + " with " + paramCount + " parameters.");
                }
                MethodInfo method = methods.get(0);
                ParameterInfo[] parameters = method.getParameters();
                for (int i = 0; i < method.getParameterCount(); i++) {
                    setStateCheckerParamType(String.valueOf(i), SourceType.of(parameters[i].getType()));
                    setStateCheckerName(String.valueOf(i), parameters[i].getName());
                }
                setStateCheckerExceptionTypes(method.getExceptionTypes());
            } else {
                throw new NoSuchMethodException("can not find method " + methodName + " in class " + type + " with " + paramCount + " parameters.");
            }
        } catch (ClassNotFoundException | NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Sets param type.
     *
     * @param index the index
     * @param type  the type
     */
    public void setStateCheckerParamType(String index, Type type) {
        getStateChecker().getParams().get(index).setType(type);
    }

    /**
     * Sets param name.
     *
     * @param index the index
     * @param name  the name
     */
    public void setStateCheckerName(String index, String name) {
        getStateChecker().getParams().get(index).setName(name);
    }

}
